package top.zhenganwen.security.core.social.qq.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.social.oauth2.AbstractOAuth2ApiBinding;
import org.springframework.social.oauth2.TokenStrategy;
import top.zhenganwen.security.core.social.qq.QQUserInfo;

/**
 * @author zhenganwen
 * @date 2019/9/3
 * @desc QQApiImpl  拿token调用开放接口获取用户信息
 * 1.首先要根据 https://graph.qq.com/oauth2.0/me/{token} 获取用户在社交平台上的id => {@code openId}
 * 2.调用QQ OpenAPI https://graph.qq.com/user/get_user_info?access_token=YOUR_ACCESS_TOKEN&oauth_consumer_key=YOUR_APP_ID&openid=YOUR_OPENID
 * 获取用户在社交平台上的信息 => {@link QQApiImpl#getUserInfo()}
 * <p>
 * {@link AbstractOAuth2ApiBinding}
 * 帮我们完成了调用OpenAPI时附带{@code token}参数, 见其成员变量{@code accessToken}
 * 帮我们完成了HTTP调用, 见其成员变量{@code restTemplate}
 * <p>
 * 注意：该组件应是多例的，因为每个用户对应有不同的OpenAPI，每次不同的用户进行QQ联合登录都应该创建一个新的 {@link QQApiImpl}
 */
@Data
public class QQApiImpl extends AbstractOAuth2ApiBinding implements QQApi {

    private static final String URL_TO_GET_OPEN_ID = "https://graph.qq.com/oauth2.0/me?access_token=%s";

    // 因为父类会帮我们附带token参数，因此这里URL忽略了token参数
    private static final String URL_TO_GET_USER_INFO = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s";

    private ObjectMapper objectMapper = new ObjectMapper();

    private String openId;

    private String appId;

    private Logger logger = LoggerFactory.getLogger(getClass());

    public QQApiImpl(String accessToken,String appId) {
        // 调用OpenAPI时将需要传递的参数附在URL路径上
        super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
        this.appId = appId;

        // 获取用户openId, 响应结果格式：callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
        String responseForGetOpenId = getRestTemplate().getForObject(String.format(URL_TO_GET_OPEN_ID, accessToken), String.class);
        logger.info("获取用户对应的openId:{}", responseForGetOpenId);

        this.openId = StringUtils.substringBetween(responseForGetOpenId, "\"openid\":\"", "\"}");
    }

    @Override
    public QQUserInfo getUserInfo() {
        // QQ互联的响应 Content-Type 都是 text/html，因此不能直接转为 QQUserInfo
//        QQUserInfo qqUserInfo = getRestTemplate().getForObject(String.format(URL_TO_GET_USER_INFO, appId, openId), QQUserInfo.class);
        String responseStr = getRestTemplate().getForObject(String.format(URL_TO_GET_USER_INFO, appId, openId), String.class);
        logger.info("调用QQ OpenAPI获取用户信息: {}", responseStr);
        try {
            QQUserInfo qqUserInfo = objectMapper.readValue(responseStr, QQUserInfo.class);
            qqUserInfo.setOpenId(openId);
            return qqUserInfo;
        } catch (Exception e) {
            logger.error("获取用户信息转成 QQUserInfo 失败，响应信息:{}", responseStr);
            return null;
        }
    }
}
